/*
-----------------------------------------------------------------------------
This file is part of NxGraphics, Multimedia Engine.
Author : Stephane Kyles. Developed in Prague, Czech Republic.
		_   __       ______                     __     _            
	   / | / /_  __ / ____/_____ ____ _ ____   / /_   (_)_____ _____
	  /  |/ /| |/_// / __ / ___// __ `// __ \ / __ \ / // ___// ___/
	 / /|  /_>  < / /_/ // /   / /_/ // /_/ // / / // // /__ (__  ) 
	/_/ |_//_/|_| \____//_/    \__,_// .___//_/ /_//_/ \___//____/  
									/_/                             
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/
#ifndef __NXCOREENGINE_H__
#define __NXCOREENGINE_H__

#include "NxGraphics_Prerequisites.h"
#include "..\Dependencies\OGRE\SDK\include\OGRE\OgreRenderSystem.h"
#include "..\Dependencies\OGRE\SDK\include\OGRE\OgreWindowEventUtilities.h"

namespace NxGraphics_Namespace {


class NxGraphics_Export NxEngineListener
{
public :
	NxEngineListener(){}
	virtual ~NxEngineListener(){}
	virtual void OnWindowMoved( unsigned int PosX, unsigned int PosY ) = 0;
	virtual void OnWindowResized( unsigned int Width , unsigned int Height ) = 0;
	virtual bool OnWindowClosing() = 0;
	virtual void OnWindowClosed() = 0;
	virtual void OnWindowFocusChange() = 0;
};


class NxGraphics_Export NxEngine : public Singleton<NxEngine>, public Ogre::WindowEventListener, public Ogre::RenderSystem::Listener
{
public :
	//! NxEngine class Constructor.
	NxEngine();
	//! NxEngine class Destructor.
	~NxEngine();
	//! NxEngine Singleton.
	static NxEngine& getSingleton();
	//! NxEngine Singleton.
	static NxEngine* getSingletonPtr();
	//! Add Listener;
	void AddListener( NxEngineListener * Listener );
	//! Remove Listener;
	void RemoveListener( NxEngineListener * Listener );
	//! Update One Frame.
	bool Update();
	//! Is Device Lost
	bool IsDeviceLost();
	//! Set Focus on Main Window.
	void SetFocus();
	//! Initializes the Engine with specific parameters.
	void InitializeEngine( const NxGraphicsDesc& engineDesc );
	//! Post initialize callback
	void PostInitialized();
	//! ShutDown the Engine.
	void ShutDownEngine();
	//! Start main loop.
	void StartRendering();
	//! Is Running.
	bool IsRendering();
	//! Pause the Engine or resume.
	void PauseEngine( bool Pause );
	//! Get User Desired Window Width.
	float GetWidth();
	//! Get User Desired Window Height.
	float GetHeight();
	//! Set Top Left Window Position.
	void SetWindowPosition( unsigned int Left, unsigned int Top );
	//! Resize Window
	void SetWindowSize( unsigned int Width, unsigned int Height );
	//! trigger position / size callbacks
	void UpdateWindowMetrics();
	//! Get Window Fps
	float GetFps();
	//! Get Window Native Handle ( on windows it will be HWND ).
	void * GetWindowNativeHandle();
	//! Set Main Window Fullscreen With Specific Parameters.
	void SetFullscreen( bool FullScreen, int Width, int Height );
	//! Is the main Window in full screen mode.
	bool IsFullscreen();
	//! Is Camera in Othogonal Projection
	bool IsProjectionOrthogonal();
	//! Set Camera in Perspective Projection
	void SetProjectionPerspective();
	//! Set Camera in Orthogonal Projection
	void SetProjectionOrthogonal( Ogre::Camera * camera, float Pan_X, float Pan_Y, float Zoom );
	//! Get Media Path.
	const std::string & GetNxMediaPath();
	//! Set Polygon View Mode.
	void SetPolygonViewMode( Ogre::PolygonMode Mode );
	//! Get Ogre RenderWindow.
	Ogre::RenderWindow * GetNxWindow();
	//! Get Ogre Main Camera.
	Ogre::Camera * GetNxCamera();
	//! Get Ogre Main SceneManager.
	Ogre::SceneManager * GetNxSceneManager();
	//! Get Ogre Main Viewport.
	Ogre::Viewport * GetNxViewport(); 
	//! Get Ogre Main Root.
	Ogre::Root * GetNxRoot();

	Ogre::Matrix4 BuildScaledOrthoMatrix( Ogre::Real left, Ogre::Real right, Ogre::Real bottom, Ogre::Real top, Ogre::Real NearPlane, Ogre::Real FarPlane );
	

private:
	bool RenderFrame( unsigned long elapsedMS );

	void windowMoved( Ogre::RenderWindow * rw );
	void windowResized( Ogre::RenderWindow * rw );
	bool windowClosing( Ogre::RenderWindow * rw );
	void windowClosed( Ogre::RenderWindow * rw );
	void windowFocusChange( Ogre::RenderWindow * rw );
	void eventOccurred( const Ogre::String& eventName, const Ogre::NameValuePairList * parameters);

	void SetupRenderer( Ogre::Real width, Ogre::Real height, NxRendererType Render_Type, NxRendererGlOptions OpenGL_Options );
	void CreateResources();
	void CheckCapabilities();

	ProgressBar * mProgressBar;
	
	bool m_RenderStop;
	bool m_DeviceLost;
	bool IsResized();
	bool m_Resized;
	bool mShutdown;
	bool m_Orthogonal ;
	bool m_Fullscreen;
	bool m_HasPreviewWindow;
	bool m_PauseRendering;
	Ogre::Real m_Width  ;
	Ogre::Real m_Height ;
	NxRendererType m_RenderSystem;
	NxRendererGlOptions m_RenderOptions;
	HWND PreviewWindowHandle ;

	Ogre::SceneManager * mSceneManager;
	Ogre::RenderWindow * mWindow;
	Ogre::Root * mRoot;
	Ogre::Viewport * mViewport;
	Ogre::Camera * mCamera;

	Ogre::RenderSystem * NxRenderSystem;
	std::string NxMediaPath;

	std::list< NxEngineListener * > mListener;

};

template<> NxEngine* Singleton<NxEngine>::ms_Singleton = 0;

} // NxGraphics_Namespace  
#endif